//
// Created by leslie on 11/10/15.
//

#include "cepollserver.h"
using namespace std;

CEpollServer::CEpollServer()
{
}

CEpollServer::~CEpollServer()
{
    close(m_isock);
}

bool CEpollServer::InitServer(const char* pIp, int iPort)
{
    m_iEpollFd = epoll_create(_MAX_SOCKFD_COUNT);

    int opts = O_NONBLOCK;
    if(fcntl(m_iEpollFd, F_SETFL, opts) < 0)
    {
        std::cout << "Failed to set the non-block model" << std::endl;
        return false;
    }

    m_isock = socket(AF_INET, SOCK_STREAM, 0);
    if ( 0 > m_isock)
    {
        std::cout << "Socket error !" << std::endl;
        return false;
    }

    sockaddr_in listen_addr;
    listen_addr.sin_family = AF_INET;
    listen_addr.sin_port = htons(iPort);
    //listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    listen_addr.sin_addr.s_addr = inet_addr(pIp);

    int ireuseadd_on = 1;
    setsockopt(m_isock, SOL_SOCKET, SO_REUSEADDR, &ireuseadd_on, sizeof(ireuseadd_on));

    if(bind(m_isock, (sockaddr*)&listen_addr, sizeof(listen_addr)) != 0)
    {
        std::cout << "Bind error !" << std::endl;
        return false;
    }

    if(listen(m_isock, 20) < 0)
    {
        std::cout << "Listen error!" << std::endl;
        return false;
    }
    else
    {
        std::cout << "Server is listening....." << std::endl;
    }

    if(pthread_create(&m_ListenThreadId, 0, (void * (*)(void *) )ListenThread, this) != 0)
    {
        std::cout << "Failed to create the server thread..." << std::endl;
        return false;
    }

}

void CEpollServer::ListenThread(void* ipVoid)
{
    CEpollServer *pTerminalServer = (CEpollServer*)ipVoid;
    sockaddr_in remote_addr;

    int len = sizeof(remote_addr);
    while(true)
    {
        int client_socket = accept(pTerminalServer->m_isock, (sockaddr*)&remote_addr, (socklen_t*)&len);
        if (client_socket < 0)
        {
            std::cout << "Server Accept error, client_socket: " << client_socket << std::endl;
            continue;
        }
        else
        {
            struct epoll_event ev;
            ev.events = EPOLLIN | EPOLLERR | EPOLLHUP;
            ev.data.fd = client_socket;
            epoll_ctl(pTerminalServer->m_iEpollFd, EPOLL_CTL_ADD, client_socket, &ev);
        }
    }
}

void  CEpollServer::Run()
{
    while(true)
    {
        struct epoll_event events[_MAX_SOCKFD_COUNT];
        int nfds = epoll_wait(m_iEpollFd, events, _MAX_SOCKFD_COUNT, -1);

        for (int i = 0; i<nfds; i++)
        {
            int client_socket = events[i].data.fd;
            char buffer[1024];
            memset(buffer, 0, 1024);
            if(events[i].events & EPOLLIN) //read signal
            {
                int rev_size = recv(events[i].data.fd, buffer, 1024, 0);
                if(rev_size <=0)
                {
                    std::cout << "recv error :recv size:" << rev_size <<std::endl;
                    struct epoll_event event_del;
                    event_del.data.fd = events[i].data.fd;
                    event_del.events = 0;
                    epoll_ctl(m_iEpollFd, EPOLL_CTL_DEL, event_del.data.fd, &event_del);
                }
                else
                {
                    std::cout << "Terminal Recevied Msg Content: " << buffer << std::endl;
                    struct epoll_event ev;
                    ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP;
                    ev.data.fd = client_socket;
                    epoll_ctl(m_iEpollFd, EPOLL_CTL_MOD, client_socket, &ev);
                }

            }
            else if(events[i].events & EPOLLOUT)//write
            {
                char sendbuffer[1024];
                sprintf(sendbuffer,"Hello, client fd:%d\n",client_socket);

                int sendsize = send(client_socket, sendbuffer, strlen(sendbuffer) + 1, MSG_NOSIGNAL);
                if (sendsize <= 0 )
                {
                    struct epoll_event event_del;
                    event_del.data.fd = events[i].data.fd;
                    event_del.events = 0;
                    epoll_ctl(m_iEpollFd, EPOLL_CTL_DEL, event_del.data.fd, &event_del);
                }
                else
                {
                    std::cout << "Server reply msg ok! buffer: %s \n" << std::endl;
                    struct  epoll_event ev;
                    ev.events = EPOLLIN | EPOLLERR | EPOLLHUP;
                    ev.data.fd = client_socket;
                    epoll_ctl(m_iEpollFd, EPOLL_CTL_MOD, client_socket, &ev);
                }
            }
            else
            {
                std::cout << "EPOLL ERROR\n" << std::endl;
                epoll_ctl(m_iEpollFd, EPOLL_CTL_DEL, events[i].data.fd, &events[i]);
            }
        }
    }
}
